\documentclass[a4paper,12pt]{article}
\usepackage[MeX]{polski}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage[left=3.0cm,right=3.0cm,top=3.0cm,bottom=3.0cm]{geometry}
\usepackage{url}
\usepackage{setspace}
\usepackage{indentfirst}
\usepackage{graphicx}
\usepackage{float}
\usepackage[nottoc]{tocbibind}


\title{Rozproszona baza danych wielooddziałowej wypożyczalni samochodów}
\author{Radosław Wyroślak 171056 \and Jakub Matczak 171164}
\date{\today}

\begin{document}
\begin{titlepage}
\begin{singlespacing}
    \begin{center}\huge\textsc
        {Politechnika Wrocławska\\Wydział Elektroniki}
    \end{center}
    \noindent\rule{\textwidth}{.1pt}
    \begin{flushleft}\large\textsc
        {Kierunek: Informatyka\\
         Specjalność: Inżynieria systemów informatycznych}
    \end{flushleft}
    \vspace{0.5cm}
    \begin{center}\Huge\textsc
        {Rozproszone i Obiektowe\\Bazy Danych\\
        Projekt}
    \end{center}
    \vspace{1cm plus 1fill}
    \begin{flushright}\LARGE
        \begin{tabular}{c}
           Rozproszony system \\ wypożyczalni samochodów
            \\ \\
            \LARGE\textsc{Autorzy:} \\
            \large{Radosław Wyroślak 171056} \\ 
            \large{Jakub Matczak 171164} \\
        \end{tabular}
    \end{flushright}
    \vspace{1cm plus 1fill}
    \begin{flushright}\LARGE
        \begin{tabular}{l}
            \textsc{Prowadzący pracę:}\\
            \large{dr inż. Robert Wójcik }\\
            \\
            \textsc{Ocena pracy:}
        \end{tabular}
    \end{flushright}
    \vspace{2cm plus 1fill}
    \noindent\rule{\textwidth}{.1pt}
    \begin{center}\large
        {WROCŁAW 2013}
    \end{center}
\end{singlespacing}
\end{titlepage}


\tableofcontents
\listoffigures
\listoftables
\newpage

\section{Cel i zakres pracy}
\subsection{Cel pracy}
Celem pracy jest zapoznanie się z mechanizmem replikacji danych w środowisku bazodanowym Oracle 11g poprzez projekt i implementację systemu wieloodziałowej wypożyczalni samochodów. System stosować będzie rozproszoną bazę danych wykorzystującą technologię Oracle Streams do synchronizacji danych pomiędzy oddziałami.
\subsection{Zakres pracy}
Projekt obejmuje następujące zagadnienia oraz aspekty:
\begin{itemize}
\item zaznajomienie się z mechanizmami replikacji w środowisku Oracle,
\item projekt bazy danych wykorzystywanej przez system,
\item implementacja mechanizmu replikacji oraz schematu bazy danych,
\item stworzenie aplikacji klienckiej służącej do odczytywania oraz zapisywania danych do bazy danych,
\item testy systemu.
\end{itemize}
Wykonanie powyższych punktów zostanie szczegółowo opisane w niniejszej pracy.

\section{Replikacja w środowisku Oracle}
\subsection{Migawki}
\label{subsec:migawki}
Migawki, inaczej zwane perspektywami zmaterializowanymi, to jeden z podstawowych mechanizmów replikacji danych w środowisku Oracle. Perspektywa zmaterializowana standardowo składa się z następujących elementów:
\begin{itemize}
\item nazwy,
\item momentu wypełnienia danymi,
\item sposobu odświeżania perspektywy,
\item momentu rozpoczęcia automatycznego odświeżania,
\item częstotliwości odświeżania migawki,
\item typu migawki,
\item zapytania określającego zakres danych w migawce.
\end{itemize}

Migawkę tworzy się wywołując polecenie \texttt{create snapshot}. Momentem, w którym migawka wypełnia się danymi może być pierwsze odświeżenie migawki lub chwila, w której migawka jest tworzona. Odświeżenie migawki oznacza aktualizację danych, które migawka przechowuje.

Odświeżenie może przebiegać dwojako: w sposób przyrostowy lub pełny. Domyślnie migawka odświeżana jest w dynamicznie - jeżeli istnieje taka możliwość w sposób przyrostowy, jeżeli nie to aktualizowane są wszystkie dane migawki. Sam proces odświeżania może być wywołany ręcznie, automatycznie, gdy dane źródłowe ulegną zmianie lub automatycznie z zadaną częstotliwością odświeżania. Istnieje także opcja wyłączenia procesu odświeżania migawki - w tym przypadku migawka zostanie wypełniona danymi raz, w momencie jej stworzenia.

Wyróżnia się dwa typy migawki: \emph{ROWID} oraz {primary key}.  Migawka typu \emph{ROWID} wykorzystuje fizyczne adresy rekordów na dysku. W przypadku przeniesienia tabeli z jednego pliku do innego, eksportu tabeli, a następnie jej importu wymagana jest pełna aktualizacja danych w migawce. Migawka typu \emph{primary key} identyfikuje źródło za pomocą klucza podstawowego tabeli źródłowej, co eliminuje powyższe problemu i możliwe jest w praktycznie każdym przypadku odświeżenie migawki w sposób przyrostowy.

Zapytaniem określającym zakres danych w migawce zazwyczaj jest zapytanie typu \texttt{SELECT}.

Dla tabeli źródłowej migawki należy utworzyć dziennik migawki. W dzienniku rejestrowane są wszystkie polecenia DML. Informacje te służą do odświeżania przyrostowego migawki. Dziennik migawki tworzony jest poleceniem \texttt{create snapshot log}.
\subsection{Zaawansowana replikacja}
Zaawansowana replikacja systemu Oracle w wersji Enterprise, umożliwiająca zbudowanie wydajnych środowisk replikacji o różnych konfiguracjach, z możliwością wykorzystania różnych platform systemowych. Zaawansowana replikacja Oracle operuje na następujących komponentach\cite{replikacja}:
\begin{itemize}
\item Obiekt replikacji - obiekt bazy danych, który podlega replikacji i istnieje na wszystkich serwerach w środowisku replikacyjnym. Przykładowe obiekty replikacji to tabele, indeksy, widoki, procedury, zdefiniowane przez użytkownika typy, wyzwalacze, synonimy i operatory.
\item Grupy replikacji - grupy logicznie ze sobą powiązanych obiektów replikacji stworzone w celu ułatwienia administracją systemu replikacji. Pojedyncza grupa najczęściej zawiera obiekty jednego schematu (np. wykorzystywane przez jedną aplikację. Jeden obiekt może należeć do jednej grupy replikacji.
\item Węzły replikacji - tworzą środowisko replikacji, definiuje się w nich grupy replikacji. Węzły mogą być nadrzędne (ang. master site) lub migawkowe (ang. materialized view site). Węzeł środowiska może być węzłem nadrzędnym dla jednej grupy replikacji i jednocześnie węzłem migawkowym dla innej grupy replikacji. Jednak jeden węzeł nie może być jednocześnie węzłem nadrzędnym i węzłem migawkowym 
dla tej samej grupy replikacji.
\end{itemize}

\subsubsection{Typy zaawansowanej replikacji}
Można wyróżnić 3 typy zaawansowanej replikacji\cite{stanford}:
\begin{enumerate}
\item Replikacja multimaster (ang. multimaster replication),
\item Replikacja migawkowa (ang. materialized view replication),
\item Replikacja hybrydowa (ang. hybrid replication)
\end{enumerate}

W środowisku replikacji \textbf{multimaster} wszystkie węzły replikacji są równoważne - każdy węzeł jest węzłem nadrzędnym. Oznacza to, że zmiana wprowadzona w  którymkolwiek  węźle  zostaje  zaaplikowana  we  wszystkich  pozostałych  węzłach  środowiska, a replikowane obiekty są identyczne we wszystkich węzłach - zarówno pod względem struktury, jak i zawartości. Każdy węzeł utrzymuje połączenie ze wszystkimi pozostałymi węzłami.\cite{replikacja}

\begin{figure}[H]
\centering
\includegraphics{multimaster.png}
\caption{Przykładowy schemat replikacji multimaster}
\label{fig:multimaster-schema}
\end{figure}

Środowisko \textbf{replikacji migawkowej} najczęściej tworzy jeden węzeł nadrzędny oraz wiele węzłów migawkowych. Grupa replikacji w węźle nadrzędnym zawiera obiekty (tabele), będące źródłami danych dla migawek, należących do grup replikacji w węzłach  migawkowych.  Węzłem  nadrzędnym  może  być  również  węzeł  migawkowy,  wówczas źródłami danych są zdefiniowane w nim migawki (jest to tzw. architektura wielowarstwowa)\cite{replikacja}. W domyślnej konfiguracji węzły migawkowe dostarczają wyłącznie operacje odczytu bazy danych. Można je także skonfigurować tak, by możliwa była modyfikacja danych w migawce. Zmodyfikowane dane w migawce są replikowane do węzła nadrzędnego. Dokładniejszy opis systemu migawek zawarty został w rozdziale \ref{subsec:migawki}.

\begin{figure}[H]
\centering
\includegraphics{mview.png}
\caption{Przykładowy schemat replikacji migawkowej}
\label{fig:mview-schema}
\end{figure}

\textbf{Replikacja  hybrydowa} jest  kombinacją  dwóch  wcześniej  wymienionych  typów  środowisk  replikacji.  Środowisko  replikacji  hybrydowej  zawiera  wiele  węzłów nadrzędnych wraz z wieloma węzłami migawkowymi. 

\begin{figure}[H]
\centering
\includegraphics{hybrid.png}
\caption{Przykładowy schemat replikacji hybrydowej}
\label{fig:hybrid-schema}
\end{figure}

\subsection{Strumienie Oracle}
Oracle Streams to uniwersalna technologia zdarzeniowej replikacji danych pomiędzy wieloma bazami danych Oracle. Oracle Streams umożliwia m.in. budowę środowisk replikacyjnych o topologii jeden-do-jednego,  jeden-do-wielu,  wiele-do-jednego,  wiele-do-wielu,  środowisk  klasy  Single-Master i Multimaster, środowisk replikacji pośredniej, itp.\cite{strumienie}

Podstawowa idea technologii Oracle Streams opiera się na użyciu trzech typów komponentów programowych\cite{strumienie}\cite{streams}: 
\begin{enumerate}
\item Capture, który prowadzi nasłuch operacji wykonywanych przez użytkowników w systemie źródłowym,
\item Propagate, który przesyła wychwycone operacje do systemu docelowego,
\item Apply,  powiela te operacje w docelowej bazie danych.
\end{enumerate}

Do obserwacji (nasłuchu) operacji wykonywanych w źródłowej bazie danych przez użytkowników wykorzystuje się dziennik powtórzeń. Do tymczasowego przechowywania wychwyconych operacji służą struktury kolejkowe Oracle Advanced Queueing. Replikowane operacje mogą być automatycznie filtrowane i transformowane w każdym punkcie architektury systemu.

Przed wykorzystaniem technologii Strumieni Oracle należy zaznajomić się z następującymi terminami\cite{strumienie}\cite{streams}:
\begin{itemize}
\item Dziennik powtórzeń - podstawowe  źródło  informacji  o  operacjach modyfikacji  danych  wykonywanych  przez użytkowników w systemie źródłowym.
Jest to  plikowy  bufor  cykliczny, w  którym każdy system zarządzania bazą danych Oracle rejestruje realizowane operacje  DML i DDL.
\item Obiekty LCR - \emph{Logical Change Records} - obiekty, które reprezentują zmiany  dokonywane  w  bazie  danych  przez  użytkowników  posługujących  się  poleceniami DML oraz DDL. W przypadki poleceń DDL często określane obiektami DDL LCR.
\item Struktury kolejkowe Oracle AQ - służą do tymczasowego przechowywania obiektów LCR. Każda kolejka AQ  umożliwia  przechowywanie obiektów  jednego  typu  danych. Podstawowymi operacjami wykonywanymi w odniesieniu do kolejek AQ są operacje umieszczenia w kolejce (Enqueue) i pobrania z kolejki (Dequeue). 
\end{itemize}

\paragraph*{Detekcja zmian} dokonywanych przez użytkowników w źródłowej bazie danych jest realizowana przez wymieniony wcześniej proces Capture, który prowadzi analizę plików dziennika powtórzeń w celu ekstrakcji opisów zmian DML i DDL dokonywanych przez użytkowników bazy danych. Na postawie opisów w generuje obiekty LCR, które następnie umieszcza we wskazanej strukturze kolejkowej.

Proces Capture może być wykorzystywany w dwóch konfiguracjach: detekcji lokalnej (Local Capture) i detekcji zdalnej (Downstream Capture). Z detekcją lokalną mamy do czynienia wtedy, kiedy proces Capture pracuje na tym samym komputerze, na którym znajduje się system zarządzania źródłową bazą danych. Obiekty LCR są wtedy tworzone wprost na podstawie zawartości plików  bieżącego  dziennika  powtórzeń.  Detekcja  zdalna  polega  na  osadzeniu  procesu  Capture  po stronie docelowego systemu zarządzania bazą danych i na wykorzystaniu mechanizmów transportu plików dziennika powtórzeń LGWR/RFS lub ARC. W ramach tego rozwiązania, pliki dziennika 
powtórzeń powstające po stronie źródłowej bazy danych są w niezmienionej postaci transferowane do systemu docelowego i dopiero tam podlegają analizie, w wyniku której są generowane i kolejkowane  obiekty  LCR.

Zaletami  wykorzystywania  zdalnej  konfiguracji  procesu  detekcji  zmian  są  m.in.:  odciążenie systemu źródłowego, gdyż przetwarzanie plików dziennika powtórzeń odbywa się w środowisku 
docelowym, a także prostota architektury w przypadku, gdy replikacja następuje z wielu systemów źródłowych do jednego systemu docelowego. Należy jednak podkreślić występujące tu zagrożenia dla poufności danych, gdyż transferowane dzienniki powtórzeń mogą zawierać także te informacje, które nie podlegają replikacji i nie powinny być udostępniane. 

\paragraph*{Propagacja zmian} do systemu docelowego realizowana jest za pomocą wymienionego procesu Propagate.  Proces odczytuje obiekty LCR z kolejki w systemie źródłowym, a następnie zapisuje je do kolejki w systemie docelowym. Przesłane obiekty są usuwane z kolejki w systemie źródłowym. Opisywany proces funkcjonuje jako zadanie wsadowe (Job) po stronie systemu źródłowego. 

Propagacja zmian działa  w  trybie  zegarowym  –  jest  uruchamiany  w  regularnych  odstępach czasu określonych przez administratora.

\paragraph*{Aplikowanie zmian} przeprowadzane jest przy pomocy procesu Apply, który pobiera obiekty LCR ze struktury kolejkowej i wykonuje opisane w nich operacje. Jeżeli operacje te nie mogą być poprawnie wykonane, np. z powodu braku tabeli o nazwie takiej, jak w systemie źródłowym, to cała wadliwa transakcja (jej obiekty LCR) jest przepisywana do wyróżnionej struktury kolejkowej nazywanej kolejką błędów (Error Queue).

\section{Analiza wymagań projektowych}
\subsection{Idea działania systemu - schemat logiczny}
System składa się z centralnej bazy danych, do której będą podłączone bazy podrzędne. Replikacja będzie odbywać się dwustronnie pomiędzy centralną bazą danych, a bazami podrzędnymi. Centralna baza danych umiejscowiona jest w centrali firmy, a bazy podrzędne w oddziałach firmy. Klienci mogą podłączać się zarówno do bazy centralnej, jak i baz podrzędnych. Zmiany wprowadzone w bazie centralnej są propagowane do wszystkich baz podrzędnych. Zmiany w jednej z baz podrzędnych są najpierw propagowane do bazy centralnej, a następnie baza centralna przesyła ja do wszystkich pozostałych baz podrzędnych.

Rozwiązanie ogranicza zużycie pasma w oddziałach firmy, ale wymaga niezawodności i dostępności bazy centralnej w celu zachowania spójności bazy danych we wszystkich oddziałach.

Na rysunku \ref{fig:logical-schema} przedstawiono schemat logiczny systemu, w którym istnieje baza centralna CR1 oraz dwie bazy podrzędne CR2 i CR3. Dwustronna komunikacja zachodzi pomiędzy CR1 i CR2 oraz CR1 i CR3.

\begin{figure}[H]
\centering
\includegraphics[width=1.0\textwidth]{logic.png}
\caption{Schemat logiczny systemu dla 3 baz danych}
\label{fig:logical-schema}
\end{figure}

\subsection{Wymagania funkcjonalne}
Projekt ma na celu dostarczenie podstawowych funkcji obsługi wieloodziałowej wypożyczalni samochodów. Zaimplementowane funkcjonalności obejmują:
\begin{itemize}
\item obsługę klientów wypożyczalni,
\item prezentowanie historii wypożyczeń wybranego klienta,
\item tworzenie nowych zleceń wypożyczenia samochodu,
\item obsługę posiadanej przez firmę floty samochodów. 
\end{itemize}

Funkcja obsługi klientów odnosi się do dodawania nowych klientów oraz edycji danych klientów istniejących w systemie. 

Dla każdego klienta przewidziana jest możliwość prezentacji historii wypożyczeń danej osoby oraz przeglądania aktualnych wypożyczeń przypisanych do klienta. Prezentowane dane to okres wypożyczenia oraz wypożyczony samochód. W przypadku aktualnych wypożyczeń system powinien zapewnić możliwość zwrotu samochodu i tym samym przeniesienie wypożyczenia do historii wypożyczeń.

Tworzenie nowego zlecenia wypożyczenia samochodu odbywa się w kontekście danego oddziału. Pracownik może wybrać jeden z samochodów dostępnych w oddziale, zaznaczyć aktywnego klienta stworzyć zamówienie dla danego klienta z wybraniem daty początku i końca zamówienia. Klient nie jest zobowiązany do zwrotu samochodu w tym samym oddziale - system zapewnia możliwość zakończenia zamówienia w dowolnym z oddziałów firmy.

Pracownik każdego z oddziałów może zarządzać samochodami dostępnymi w oddziale. Proces zarządzania obejmuje dodawanie nowych samochodów, edycję parametrów dostępnych w oddziale samochodów oraz usuwanie samochodów. Dodatkowo istnieje opcja przeglądania aktualnie wypożyczonych samochodów (wszystkich, które są poza oddziałami) i sprawdzenie dat wypożyczenia oraz oddania, a także danych klienta, który wypożyczył dany samochód.

Wszystkie modyfikowane przez pracowników dane są replikowane do baz danych we wszystkich oddziałach oraz w centrali, co pozwala na zachowanie spójności danych w całym przedsiębiorstwie i daje możliwość oddania samochodu wypożyczonego w jednym oddziale w innym oddziale.

\subsection{Wymagania niefunkcjonalne}

Przewidziany w systemie system zabezpieczeń działa na zasadzie autoryzacji użytkownika systemu bazy danych. Aplikacja kliencka wczytuje z pliku konfiguracyjnego dane służące do zalogowania się w bazie danych. Użytkownik powinien być właścicielem schematu replikowanego pomiędzy oddziałami. Nie są wymagane żadne dodatkowe informacje służące do dostępu do systemu.

Wydajność systemu powinna zostać zapewniona na takim poziomie, by obsługa aplikacji klienckiej była wygodna i nie powodowała opóźnienia w czasie obsługi klienta. Aplikacja bezpośrednio przesyła zapytania do bazy danych za pomocą sterownika JDBC. System replikacji skonfigurowany jest tak, by natychmiastowo przesyłał zmiany w bazie danych do centralnego serwera, który następnie przesyła je do innych oddziałów. System działa w czasie rzeczywistym - wymagane jest by zmiany danych wprowadzone w jednym oddziale natychmiastowo pojawiały się we wszystkich innych oddziałach oraz w centrali.

Zaplanowano wyłącznie podstawową odporność na błędy użytkownika. W aplikacji klienckiej wprowadzone są jedynie pewne mechanizmy kontroli wprowadzanych danych (np. zabezpieczenie przed przypadkowym wciśnięciem klawisza nowego zamówienia i dodanie zamówienia bez daty wypożyczenia i oddania). Przy projektowaniu aplikacji przyjęte zostało założenie, że obsługiwana będzie wyłącznie przez przeszkolonych pracowników przedsiębiorstwa, zatem kompleksowa obsługa potencjalnych błędów użytkownika nie jest konieczna.

\subsection{Założenia projektowe}
Ostatecznie projekt powinien gwarantować:
\begin{enumerate}
\item kompleksową obsługę mechanizmu wypożyczenia samochodu - od wybrania klienta, przez wybranie samochodu i dat wypożyczenia oraz zwrotu, do stworzenia zamówienia i ostatecznie zaznaczenia go jako zrealizowane,
\item możliwość modyfikacji listy klientów i samochodów oraz edycji ich danych,
\item ciągłą replikację danych pomiędzy oddziałami firmy w celu zapewnienia spójności danych oraz likwidacji anomalii (np. dwie osoby wypożyczają ten sam samochód).
\end{enumerate}

\subsection{Diagram i scenariusze przypadków użycia}
Projekt można napisać przez diagram przypadków użycia przedstawiony na rysunku \ref{fig:usecases}.

\begin{figure}[H]
\centering
\includegraphics[width=1.0\textwidth]{usecase-diagram.png}
\caption{Diagram przypadków użycia systemu}
\label{fig:usecases}
\end{figure}

Jako przykłady przedstawiono scenariusze dwóch przypadków użycia.

\vspace{10pt}
{\parindent5pt
\textbf{Dodawanie klienta}

\textbf{Cel}: Dodanie nowego klienta w systemie

\textbf{Warunki początkowe}: Dane klienta

\textbf{Przebieg}:

{\parindent10pt
\begin{enumerate}
\item Kliknięcie przycisku \textit{Utwórz...} w oknie programu.
\item Wpisanie danych: imienia, nazwiska oraz numeru PESEL klienta.
\item Kliknięcie przycisku \textit{Dodaj}.
\item Alternatywnie: kliknięcie przycisku \textit{Anuluj}.
\end{enumerate}
}

\textbf{Warunki końcowe}: dodanie klienta do bazy. Alternatywnie: brak.
}

\vspace{10pt}
{\parindent5pt
\textbf{Tworzenie zamówienia}

\textbf{Cel}: Stworzenie nowego zamówienia

\textbf{Warunki początkowe}: W systemie istnieje przynajmniej jeden klient i jest wolny jeden samochód.

\textbf{Przebieg}:

{\parindent10pt
\begin{enumerate}
\item Wybór klienta z rozwijanego menu w głównym oknie programu.
\item Wybranie zakładki \textit{Nowe zamówienie} w oknie programu.
\item Wybranie jednego z dostępnych samochodów.
\item Ustawienie daty rozpoczęcia wypożyczenia i daty oddania samochodu.
\item Kliknięcie w przycisk \textit{Stwórz}.
\end{enumerate}
}

\textbf{Warunki końcowe}: dodanie klienta do bazy. Alternatywnie: brak.
}

\section{Projekt systemu}
Projekt systemu składa się z następujących kluczowych etapów:
\begin{itemize}
\item projekt bazy danych,
\item projekt systemy replikacji danych,
\item projekt aplikacji klienckiej
\end{itemize}
Dodatkowo opisany zostanie system zabezpieczeń systemu.
\subsection{Projekt bazy danych}
\subsubsection{Struktura tabel i relacji}
Struktura tabel wygląda następująco:
\begin{table}[H]
\centering
\caption{Struktura tabeli \textbf{client}}
\begin{tabular}{|c|c|}
\hline
Nazwa kolumny & Atrybuty \\ \hline
ID & NOT NULL NUMBER \\ \hline
NAME & VARCHAR2(128 CHAR) \\ \hline
SURNAME & VARCHAR2(128 CHAR) \\ \hline
ADDRESS & VARCHAR2(256) \\ \hline
\end{tabular}
\label{tab:client}
\end{table}

\begin{table}[H]
\centering
\caption{Struktura tabeli \textbf{car}}
\begin{tabular}{|c|c|}
\hline
Nazwa kolumny & Atrybuty \\ \hline
ID & NOT NULL NUMBER \\ \hline
PRODUCER & VARCHAR2(100 CHAR) \\ \hline
MODEL & VARCHAR2(100 CHAR) \\ \hline
YEAR & NUMBER \\ \hline
PRICE & NUMBER \\ \hline
BRANCH\_ID & NUMBER \\ \hline
\end{tabular}
\label{tab:car}
\end{table}

\begin{table}[H]
\centering
\caption{Struktura tabeli \textbf{branch}}
\begin{tabular}{|c|c|}
\hline
Nazwa kolumny & Atrybuty \\ \hline
ID & NOT NULL NUMBER \\ \hline
ADDRESS & VARCHAR2(256 CHAR) \\ \hline
\end{tabular}
\label{tab:branch}
\end{table}

\begin{table}[H]
\centering
\caption{Struktura tabeli \textbf{rental}}
\begin{tabular}{|c|c|}
\hline
Nazwa kolumny & Atrybuty \\ \hline
ID & NOT NULL NUMBER \\ \hline
DATE\_FROM & DATE \\ \hline
DATE\_TO & DATE \\ \hline
DATE\_RETURNED & DATE \\ \hline
PRICE & NUMBER \\ \hline
CAR\_ID & NUMBER \\ \hline
CLIENT\_ID & NUMBER \\ \hline
\end{tabular}
\label{tab:rental}
\end{table}

Poniżej zaprezentowano strukturę relacji, czyli lista wszystkich relacji wraz z ich typem.
\begin{table}[H]
\centering
\caption{Struktura relacji}
\begin{tabular}{|c|c|}
\hline
Nazwa relacji & Typ \\ \hline
Car To Rental & 1:N \\ \hline
Car To Branch & 1:N \\ \hline
Client To Rental & 1:N \\ \hline
\end{tabular}
\label{tab:relations}
\end{table}

Z powyższej struktury wynika, że istnieje także niejawna relacja wiele do wielu tabel \textbf{car} oraz \textbf{client}.


\subsubsection{Model fizyczny}
Model fizyczny bazy danych zostanie przedstawiony za pomocą diagramu relacyjnego modelu wykorzystywanej bazy danych widocznego na rysunku \ref{fig:rel-model} znajdującym się poniżej.

\begin{figure}[H]
\centering
\includegraphics[width=1.0\textwidth]{db-rel-diagram.png}
\caption{Relacyjny model bazy danych wykorzystywanej w systemie}
\label{fig:rel-model}
\end{figure}

\subsection{Projekt systemu replikacji opartego o strumienie Oracle}
\subsubsection{Architektura systemu replikacji}
W projekcie stworzono 3 bazy danych - każda znajdująca się na oddzielnej maszynie wirtualnej. Oznaczenia baz danych to kolejno:
\begin{enumerate}
\item \textbf{CR1} - baza centralna, przez którą przechodzi komunikacja.
\item \textbf{CR2} - baza w jednym z oddziałów.
\item \textbf{CR3} - baza w jednym z oddziałów.
\end{enumerate}

Baza CR1 łączy się dwukierunkowo z bazą CR2 oraz bazą CR3. Bazy CR2 i CR3 nie mają ze sobą bezpośredniego połączenia. Pełny schemat systemu replikacji przedstawiono na rysunku  \ref{fig:streams-schema}.

\begin{figure}[H]
\centering
\includegraphics[width=1.0\textwidth]{streams-schema.png}
\caption{Model systemu replikacji zastosowanego w projekcie}
\label{fig:streams-schema}
\end{figure}

\subsubsection{Uprawnienia użytkowników}
W celu konfiguracji replikacji na każdym z serwerów stworzony został administrator strumieni. Dla administratora strumieni wymagane jest stworzenie oddzielnej przestrzeni tabel. Wszystkie operacje na strumieniach powinny być wykonywane z poziomu administratora strumieni. Samą konfigurację systemu strumieni także należy przeprowadzać z konta administratora strumieni. Podczas działania systemu wszystkie informacje zapisywane są w przestrzeni nazw administratora strumieni.

Na każdym z serwerów będących częścią systemu replikacji ustanowione jest konto administratora strumieni o następujących danych:
\begin{itemize}
\item \textbf{login:} stradmin
\item \textbf{hasło:} password
\end{itemize}

\subsection{Projekt aplikacji klienckiej}

Aplikacja kliencka została zaprojektowana z wykorzystaniem technik programowania obiektowego oraz języka Java. Połączenia z bazą danych realizowane są przy pomocy sterownika Oracle JDBC. Interfejs graficzny stworzono za pomocą biblioteki Swing. Dodatkowo wykorzystano biblioteki: joda-time w celu łatwiej manipulacji datami oraz jdatepicker, która dostarcza komponent wyboru daty, który można wykorzystać w oknie interfejsu graficznego.

\subsubsection{Diagramy klas}
W projekcie zastosowano dwa pakiety klas - core oraz gui. Klasy z pierwszego pakietu obejmują logikę działania programu, natomiast klasy z pakietu gui dostarczają interfejs graficzny aplikacji.

\begin{figure}[H]
\centering
\includegraphics[width=1.0\textwidth]{core-diagram.png}
\caption{Diagram klas pakietu core}
\label{fig:core-schema}
\end{figure}

\begin{figure}[H]
\centering
\includegraphics[width=1.0\textwidth]{gui-diagram.png}
\caption{Diagram klas pakietu gui}
\label{fig:gui-schema}
\end{figure}

Dodatkowo prawie wszystkie klasy widoczne na rysunku \ref{fig:gui-schema} posiadają jako zależność klasę Engine z pakietu core. Klasa Engine to klasa typu singleton wykorzystywana do zwracania połączenia do bazy danych i udostępniająca metody modyfikacji danych w bazie. Jej pola i metody widoczne są na rysunku \ref{fig:core-schema}.

\subsubsection{Mechanizm dostępu do bazy danych}
W celu dostępu do bazy danych skorzystaliśmy z mechanizmu JDBC. Jest to interfejs, który pozwala do dostępu do baz danych różnych producentów. Interfejs wymaga podania sterownika, za pomocą którego aplikacja będzie łączyła się z bazą danych. W naszym przypadku wykorzystano oficjalne sterownik dostępu do bazy danych Oracle - Oracle Driver. Architektura interfejsu jest następująca \cite{jdbc}:

\begin{figure}[H]
\centering
\includegraphics{jdbc.png}
\caption{Architektura interfejsu JDBC}
\label{fig:jdbc}
\end{figure}

\subsection{Projekt systemu zabezpieczeń}
System nie posiada skomplikowanego systemu zabezpieczeń. W systemie baz danych Oracle każdy z użytkowników posiada własny schemat bazy danych. W każdej z baz danych będących częścią systemu replikacji istnieje użytkownik \textbf{carrent}, którego schemat jest replikowany. Każda aplikacja kliencka musi połączyć się z bazą za pomocą danych użytkownika \textbf{carrent}. Po połączeniu się z bazą aplikacja kliencka ma dostęp do replikowanych tabel i wszystkie zmiany przesyłane są do centralnej bazy danych, a następnie do baz w oddziałach.

Dane do logowania wpisuje się w pliku konfiguracyjnym aplikacji klienckiej. Plik konfiguracyjny musi zachować format standardowy dla plików Java Properties. Przykładowe dane do logowania z pliku konfiguracyjnego:
\begin{verbatim}
user=carrent
password=password
\end{verbatim}

\section{Implementacja elementów systemu}
\subsection{Realizacja bazy danych - skrypty SQL}
Skrypt w całości tworzący cała strukturę wykorzystywanej w projekcie bazy danych, bez relacji pomiędzy tabelami:
\begin{verbatim}
CREATE TABLE Branch 
    ( 
     id NUMBER  NOT NULL , 
     address VARCHAR2 (256) 
    );

ALTER TABLE Branch 
    ADD CONSTRAINT "Branch PK" PRIMARY KEY ( id ) ;

CREATE TABLE Car 
    ( 
     id NUMBER  NOT NULL , 
     producer VARCHAR2 (100 CHAR) , 
     model VARCHAR2 (100 CHAR) , 
     year NUMBER , 
     price NUMBER , 
     branch_id NUMBER 
    );

ALTER TABLE Car 
    ADD CONSTRAINT "Car PK" PRIMARY KEY ( id ) ;

CREATE TABLE Client 
    ( 
     id NUMBER  NOT NULL , 
     name VARCHAR2 (128 CHAR) , 
     surname VARCHAR2 (128 CHAR) , 
     address VARCHAR2 (256) 
    );

ALTER TABLE Client 
    ADD CONSTRAINT "Client PK" PRIMARY KEY ( id ) ;

CREATE TABLE Rental 
    ( 
     id NUMBER  NOT NULL , 
     date_from DATE , 
     date_to DATE , 
     car_id NUMBER , 
     client_id NUMBER , 
     date_returned DATE , 
     price NUMBER 
    );
ALTER TABLE Rental 
    ADD CONSTRAINT "Rental PK" PRIMARY KEY ( id ) ;
\end{verbatim}

Po stworzeniu podstawowej struktury należy wykorzystać polecenia ALTER TABLE do stworzenia relacji oraz oznaczenia kluczy obcych:
\begin{verbatim}
ALTER TABLE Car 
    ADD CONSTRAINT Branch_Car FOREIGN KEY 
    ( branch_id ) 
    REFERENCES Branch 
    ( id );
    
ALTER TABLE Rental 
    ADD CONSTRAINT Car_Rental FOREIGN KEY 
    ( car_id ) 
    REFERENCES Car 
    ( id );
    
ALTER TABLE Rental 
    ADD CONSTRAINT Client_Rental FOREIGN KEY 
    ( client_id ) 
    REFERENCES Client 
    ( id );
\end{verbatim}

\subsection{Implementacja systemu replikacji}
\subsubsection{Skrypt}
Do konfiguracji środowiska wymagane są dwa skrypty. Pierwszy ze skryptów tworzy połączenie pomiędzy bazami CR1 i CR2, drugi pomiędzy CR1 a CR3. Skrypty zostały wygenerowane za pomocą oprogramowania Enterprise Manager. Z powodu swojej objętości skrypty zostaną załączone do elektronicznej wersji dokumentacji projektu w formacie TXT.

\subsubsection{Kroki konfiguracji Enterprise Managera}
Przedstawiony zostanie przykładowy proces konfiguracji replikacji danych pomiędzy bazą centralną CR1, a bazą oddziału - CR3. Konfiguracja replikacji przebiega w następujących krokach:
\begin{enumerate}
\item Logujemy się do Enterprise Managera na koncie administratora strumieni.
\item Wybieramy z menu pozycji Data Movement, a następnie Setup Streams.
\item Po otwarciu kreatora konfiguracji strumieni ustawiamy opcję Replicate Schemas. W sekcji Host Credentials wpisujemy login i hasło użytkownika systemowego, z którego konta uruchomiona jest baza danych. Krok przedstawiono na poniższym rysunku:

\begin{figure}[H]
\centering
\includegraphics{em1.png}
\caption{Enterprise Manager - wybór sposoby replikacji}
\label{fig:em1}
\end{figure}

\item Po kliknięciu przycisku Next wybieramy schemat, który ma być replikowany. W przypadku tego projektu będzie to CARRENT.
 
\begin{figure}[H]
\centering
\includegraphics{em2.png}
\caption{Enterprise Manager - wybór schematu podlegającego replikacji}
\label{fig:em2}
\end{figure}

\item Na kolejnej podstronie uzupełniamy dane potrzebne do ustanowienia połączenia z drugą bazą danych:
\begin{itemize}
\item nazwa hosta,
\item port na którym działa baza (standardowo 1521),
\item nazwa serwisu Oracle (ustanawiana podczas instalacji),
\item login i hasło administratora strumieni na komputerze, z którym zostanie nawiązane połączenie.
\end{itemize}
Przykładowe dane:
\begin{figure}[H]
\centering
\includegraphics{em3.png}
\caption{Enterprise Manager - dane do połączenia z drugą bazą danych}
\label{fig:em3}
\end{figure}

\item W kolejnym oknie trzeba rozwinąć sekcję opcji zaawansowanych i zaznaczyć aktywację wymiany dwukierunkowej - w przeciwnym razie replikowane będą zmiany zachodzące wyłącznie w bazie centralnej CR1, zmiany wprowadzane w bazie CR3 będą tylko lokalne.
\begin{figure}[H]
\centering
\includegraphics[width=1.0\textwidth]{em4.png}
\caption{Enterprise Manager - wybór połączenia dwukierunkowego}
\label{fig:em4}
\end{figure}

\item Ostatnim etapem konfiguracji jest podsumowanie wprowadzonych ustawień. Istnieje możliwość podejrzenia i edycji skryptów konfiguracyjnych wygenrowanych przez Enterprise Managera.
\begin{figure}[H]
\centering
\includegraphics[width=1.0\textwidth]{em5.png}
\caption{Enterprise Manager - podsumowanie konfiguracji replikacji}
\label{fig:em5}
\end{figure}
\end{enumerate}

Po wykonaniu powyższych czynności konfiguracja uruchamiana jest jako zadanie (job) i wykonuje się w tle.

\subsection{Realizacja wybranych funkcjonalności systemu}
\subsubsection{Dodawanie nowego użytkownika}
W celu dodania nowego użytkownika należy kliknąć przycisk Utwórz, a następnie po wpisaniu danych przycisk Dodaj. Przy kliknięciu przycisku wywołuje się metoda:
\begin{verbatim}
public void actionPerformed(ActionEvent arg0) {
   if (txtName.getText().equals("")
|| txtSurname.getText().equals(""))
      return;
   try {
      Engine e;
      e = Engine.getInstance();
      e.insertClient(txtName.getText(), txtSurname.getText(),
   txtAddress.getText());
      dispose();
      clientPanel.refreshClients();
   } catch (SQLException | IOException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
   }
\end{verbatim}

Rekord do bazy dodaje metoda insertClient() klasy Engine:
\begin{verbatim}
public void insertClient(String name, String surname, String address)
      throws SQLException {
   String query = "INSERT INTO client VALUES(client_pk_seq.nextval, '"
         + name + "', '" + surname + "', '" + address + "')";
   Statement stmt = dbh.createStatement();
   stmt.executeUpdate(query);
   dbh.commit();
   stmt.close();
}
\end{verbatim}
Zapytanie jest przesłane zwykłym sposobem, nie za pomocą zapytania preparowanego. Może to stanowić zagrożenie dla bezpieczeństwa.

\subsubsection{Pobranie list wypożyczeń}
Aktualne i historyczne zamówienia pobiera się za pomocą dwóch metod klasy Engine:
\begin{verbatim}
public List<Rental> getActualRents(int clientId) 
      throws SQLException {
   String query = "select * from rental where " +
         "date_from=date_returned and client_id="
         + clientId;
   return getRentsByQuery(query);
}
public List<Rental> getHistoryRents(int clientId) 
      throws SQLException {
   String query = "select * from rental where " +
         "date_from<date_returned and client_id="
         + clientId;
   return getRentsByQuery(query);
}
\end{verbatim}

Metody korzystają z prywatnej metody pobierającej zlecenia w zależności od zapytania:
\begin{verbatim}
private List<Rental> getRentsByQuery(String query) 
      throws SQLException {
   List<Rental> rents = new LinkedList<>();
   Statement stmt = dbh.createStatement();
   ResultSet rs = stmt.executeQuery(query);
   Rental rental;
   while (rs.next()) {
      rental = new Rental();
      rental.setId(rs.getInt("id"));
      rental.setDateFrom(rs.getDate("date_from"));
      rental.setDateTo(rs.getDate("date_to"));
      rental.setCarId(rs.getInt("car_id"));
      rental.setClientId(rs.getInt("client_id"));
      rental.setDateReturned(rs.getDate("date_returned"));
      rental.setPrice(rs.getDouble("price"));
      rents.add(rental);
   }
   stmt.close();
   return rents;
}
\end{verbatim}

\subsubsection{Tworzenie zamówienia}
Po wybraniu samochodu i klienta oraz kliknięciu przycisku Stwórz wywoływana jest metoda:
\begin{verbatim}
public void actionPerformed(ActionEvent arg0) {
   DateModel<Calendar> toModel = (DateModel<Calendar>) datePickerTo
.getModel();
   DateModel<Calendar> fromModel = (DateModel<Calendar>) datePickerFrom
.getModel();
   Calendar fromCalendarDate = fromModel.getValue();
   Calendar toCalendarDate = toModel.getValue();
   if (toModel.getValue() == null
|| listCars.getSelectedIndex() == -1)
      return;
   Date fromSqlDate = new Date(fromCalendarDate.getTime()
.getTime());
   Date toSqlDate = new Date(toCalendarDate.getTime().getTime());
   try {
      Engine e = Engine.getInstance();
      int carId = listCars.getSelectedValue().getId();
      e.insertRental(cp.getSelectedClientId(), carId,
   fromSqlDate, toSqlDate);
      refreshList();
      cp.getBrc().refreshList();
      cp.getCrp().refreshRents(cp.getSelectedClientId());
   } catch (SQLException | IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
   }
}
\end{verbatim}

Zapytanie do bazy wykonywane jest przez metodę insertRental() klasy Engine:
\begin{verbatim}
public void insertRental(int clientId, int carId, Date from, Date to)
		throws SQLException {
	String query;
	int days = Days.daysBetween(new DateTime(from), new DateTime(to))
			.getDays();
	double price = days * getCarById(carId).getPrice();
	// insert
    query = "INSERT INTO rental VALUES(rental_pk_seq.nextval, " +
				"?, ?, ?, ?, ?, ?)";
	PreparedStatement pst = dbh.prepareStatement(query);
	pst.setDate(1, from);
	pst.setDate(2, to);
	pst.setInt(3, carId);
	pst.setInt(4, clientId);
	pst.setDate(5, from);
	pst.setDouble(6, price);
	pst.executeUpdate();
	dbh.commit();
	pst.close();
	
	// update car
	query = "UPDATE car SET branch_id=0 WHERE id=" + carId;
	Statement stmt = dbh.createStatement();
	stmt.executeQuery(query);
	dbh.commit();
	stmt.close();
}
\end{verbatim}

W tym przypadku zastosowano zapytania preparowane, co zwiększa bezpieczeństwo, ponieważ odpowiednie wartości umieszczane są w zapytaniu przez wyspecjalizowane metody klasy PreparedStatement.

\subsection{Realizacja zabezpieczeń}
\subsubsection{Zabezpieczenia w bazie danych}
Skrypt tworzący administratora strumieni:
\begin{verbatim}
CREATE USER strmadmin IDENTIFIED BY password 
   DEFAULT TABLESPACE streams_tbs
   QUOTA UNLIMITED ON streams_tbs;
   
GRANT DBA TO strmadmin;

BEGIN
  DBMS_STREAMS_AUTH.GRANT_ADMIN_PRIVILEGE(
    grantee          => 'strmadmin',    
    grant_privileges => TRUE);
END;
\end{verbatim}

Strumienie Oracle korzystają z dziennika zmian. Dziennik zmian ma też znaczenie w przypadku bezpieczeństwa - pozwala odtworzyć transakcje bazy danych w przypadku  awarii. Włączyć tryb logowania można z poziomu menu Availability $\rightarrow$ Recovery Settings.
\begin{figure}[H]
\centering
\includegraphics[width=1.0\textwidth]{archive.png}
\caption{Aktywacja dziennika zmian}
\label{fig:archive}
\end{figure}

\subsubsection{Podłączanie się do bazy}
Poniżej przedstawiono prywatną metodę klasy Engine służąca do połączenia się z bazą danych. Metoda korzysta z danych z pliku konfiguracyjnego aplikacji.
\begin{verbatim}
private void __connect(String user, String password, String hostname)
      throws SQLException {
   try {
      Class.forName("oracle.jdbc.driver.OracleDriver");
      dbh = DriverManager.getConnection("jdbc:oracle:thin:@//" + 
            hostname + ":1521/" + hostname, user, password);
      System.out.println("Pomyślnie połączono z baza danych SQL");
   } catch (ClassNotFoundException e) {
      System.out.println("Brak polaczenia.");
      e.printStackTrace();
   }
}
\end{verbatim}
\section{Testowanie systemu}
\subsection{Testy funkcjonalne}
Przetestowano dwie połączone ze sobą funkcjonalności. Najpierw dodane zostanie nowe zlecenie do bazy danych:
\begin{figure}[H]
\centering
\includegraphics{new.png}
\caption{Dodawanie nowego zlecenia}
\label{fig:new}
\end{figure}

Następnie na aplikacji klienckiej podłączonej do bazy danych innego oddziału sprawdzono, czy dane zostały poprawnie zreplikowane i wypożyczony samochód znajduje się na liście wypożyczonych samochodów.

\begin{figure}[H]
\centering
\includegraphics{cars.png}
\caption{Przeglądanie historii wypożyczeń}
\label{fig:cars}
\end{figure}

Operacja została wykonana poprawnie. Przetestowano w podobny sposób inne założone funkcjonalności i wyniki również były poprawne.

\subsection{Testy wydajnościowe}
Wszystkie operacje dodawania nowych rekordów lub aktualizacji rekordów wykonują się natychmiastowo. Połączenie z bazą także nawiązywane jest bez zastojów. Jedyne zastrzeżenia co do wydajności występują, gdy program pobiera listy różnych obiektów. Opóźnienie jest widoczne, ale nie przeszkadza w korzystaniu z programu.

Czas wykonywania się zapytań jest bardzo niski z powodu ich niewielkiej złożoności.

Replikacja działa wydajnie, po zatwierdzeniu zmian pojawiają się one od razu we wszystkich oddziałowych bazach danych.
\subsection{Wnioski z testów}
Wszystkie funkcjonalności aplikacji działają. Informacje są aktualizowane w aplikacji klienckiej po wykonaniu czynności użytkownika. Mechanizmem, który mógłby zostać zaimplementowany jest nasłuchiwanie, czy baza danych, do której podłączona jest aktualizacja została zaktualizowana przez system replikacji i automatyczny proces odświeżenia list i danych w aplikacji klienckiej. W tej chwili użytkownik musi kliknąć przycisk Odśwież wszystko w celu synchronizacją z bazą danych.

Testy wydajnościowe pokazały, że jedyny problem z wydajnością występuje przy pobieraniu list obiektów, np. listy wszystkich samochodów, listy wszystkich klientów, listy wszystkich zleceń. Rozwiązaniem tego problemu mogłoby być zastosowanie mechanizmu buforowania, który pobierałby wyłącznie nowe dane lub dane, które się zmieniły. Jednakże, przyspieszenie działania programu byłoby nieznaczne, ponieważ aktualne opóźnienia są bardzo niewielkie.

\section{Podsumowanie}
Powyższa praca obejmowała projekt i implementację systemu wieloodziałowej wypożyczalni samochodów stosujący rozproszoną bazę danych wykorzystującą technologię Oracle Streams do synchronizacji danych pomiędzy oddziałami. Podczas projektu należało zaznajomić się i zaimplementować mechanizm replikacji oparty o technologię Oracle Streams oraz zaprojektować i stworzyć bazę danych oraz aplikację kliencką do obsługi wieloodziałowej wypożyczalni samochodów.

Technologia Oracle Streams to zdarzeniowy system replikacji danych pomiędzy bazami danych Oracle. Podczas działania wykorzystuje 3 procesy - Capture do nasłuchu operacji wykonywanych przez użytkowników systemu, Propagate do przesyłania wprowadzonych zmian w bazie danych do systemu docelowego oraz Apply do powielania odebranych operacji w docelowej bazie danych.

System powinien posiadać następujące funkcjonalności:
\begin{itemize}
\item obsługę klientów - dodawanie, edycję, przeglądanie historii zamówień,
\item obsługę zleceń - tworzenie nowych,
\item obsługę samochodów - dodawanie, edycję, usuwanie.
\end{itemize}
Osobą operującą na wszystkich funkcjonalnościach systemu jest pracownik oddziału wypożyczalni samochodów posiadający dostęp do aplikacji klienckiej.

Dodatkowymi założeniami jest bezpieczeństwo danych systemu zapewnione przez mechanizm autoryzacji oraz wydajność umożliwiająca wygodne użytkowanie systemu przez pracowników wypożyczalni.

Architektura systemu zakłada, że jeden z serwerów będzie serwerem nadrzędnym znajdującym się w centrali firmy. Serwer nadrzędny będzie utrzymywał połączenia z serwerami znajdującymi się w oddziałach. Replikacja danych odbywa się dwukierunkowo pomiędzy bazą centralną, a bazami w oddziałach firmy. Oddziały firmy nie posiadają połączenia pomiędzy sobą. Takie podejście ogranicza wykorzystywane pasmo w oddziałach firmy, ale wprowadza wymaganie ciągłego działania serwera nadrzędnego w celu zapewnienia spójności danych we wszystkich bazach danych wykorzystywanych przez firmę oraz uniknięcia konfliktów.

Aplikacja kliencka napisana została przy pomocy języka Java w wersji 1.7. Połączenia z bazą danych realizowane są przy pomocy sterownika Oracle JDBC. Interfejs graficzny stworzono za pomocą biblioteki Swing. Aplikacja składa się z dwóch pakietów klas - jeden odpowiada za logikę biznesową aplikacji, przechowuje klasy reprezentujące tabele z baz danych oraz klasę Engine służącą do komunikacji z bazą danych, drugi przechowuje klasy interfejsu graficznego.

Klasa Engine zaprojektowana została z wykorzystaniem wzorca projektowego Singleton, co pozwala na dostęp do połączenia z bazą danych w każdym miejscu w programie.

Podczas pracy programu używane są zarówno zapytania standardowe do bazy danych, jak i zapytania preparowane. Zapytanie preparowane gwarantują poprawność danych przesyłanych w zapytaniu i zwiększają bezpieczeństwo pracy programu.

Przeprowadzono podstawowe testy funkcjonalne oraz wydajnościowe. Z testów funkcjonalnych wynika, że wszystkie założone funkcjonalności zostały zaimplementowane poprawnie. Dla zwiększenia wygody oraz niezawodności programu warto w przyszłości zaimplementować mechanizm aktualizacji interfejsu (list, menu rozwijanych) w czasie rzeczywistym, po aktualizacji przez system replikacji bazy danych, do której podłączony jest program. Taki mechanizm ograniczy możliwość zmniejszenia spójności bazy danych przez pochopne działania użytkownika.

Wydajność systemu jest wystarczająca. Jedyne opóźnienia występują podczas pobierania list wszystkich obiektów dostępnych w systemie. Opóźnienia można ograniczyć wdrażając mechanizm buforowania pobieranych danych z systemu i pobierania wyłącznie tych, które się zmieniły.

Zrealizowanie projektu pozwoliło na poznanie mechanizmów replikacji baz danych Oracle. Rozwiązywanie napotkanych problemów i trudności podczas konfiguracji środowiska replikacji w znaczący sposób przyczyniło się do zwiększenia naszego doświadczenia w administrowaniu rozproszonymi bazami danych.

\bibliographystyle{plplain}
\bibliography{sprawozdanie}

\end{document}